package org.papervision3d.objects.primitives {
	import org.papervision3d.Papervision3D;
	import org.papervision3d.core.geom.*;
	import org.papervision3d.core.geom.renderables.Triangle3D;
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.core.math.NumberUV;
	import org.papervision3d.core.proto.*;	

	/**
	* <span lang="ja">Plane は 3D オブジェクトの平面を作成するクラスです。</span>
	* 
	* <span lang="en">The Plane class lets you create and display flat rectangle objects.
	* The rectangle can be divided in smaller segments. This is usually done to reduce linear mapping artifacts.
	* Dividing the plane in the direction of the perspective or vanishing point,
	* helps to reduce this problem. Perspective distortion dissapears when the plane is facing straignt to the camera,
	* i.e. it is perpendicular with the vanishing point of the scene.</span>
	*/
	public class Plane extends TriangleMesh3D
	{
		/**
		* <span lang="ja">水平セグメントの数です。 デフォルトは 1 です。</span>
		* <span lang="en">Number of segments horizontally. Defaults to 1.</span>
		*/
		public var segmentsW :Number;
	
		/**
		* <span lang="ja">垂直セグメントの数です。 デフォルトは 1 です。</span>
		* <span lang="en">Number of segments vertically. Defaults to 1.</span>
		*/
		public var segmentsH :Number;
	
		/**
		* <span lang="ja">Plane のデフォルトサイズです。</span>
		* <span lang="en">Default size of Plane if not texture is defined.</span>
		*/
		static public var DEFAULT_SIZE :Number = 500;
	
		/**
		* <span lang="ja">Plane のデフォルトサイズです。</span>
		* <span lang="en">Default size of Plane if not texture is defined.</span>
		*/
		static public var DEFAULT_SCALE :Number = 1;
	
		/**
		* <span lang="ja">水平・垂直セグメントのデフォルト値です。</span>
		* <span lang="en">Default value of gridX if not defined. The default value of gridY is gridX.</span>
		*/
		static public var DEFAULT_SEGMENTS :Number = 1;
	
	
		// ___________________________________________________________________________________________________
		//                                                                                               N E W
		// NN  NN EEEEEE WW    WW
		// NNN NN EE     WW WW WW
		// NNNNNN EEEE   WWWWWWWW
		// NN NNN EE     WWW  WWW
		// NN  NN EEEEEE WW    WW
	
		/**
		* <span lang="ja">新しい Plane インスタンスを作成します。</span>
		* <span lang="en">Create a new Plane object.</span>
		* 
		* @param	material	
		* <span lang="ja">テクスチャーとして適用したいMaterialObject3Dを指定します。</span>
		* <span lang="en">A MaterialObject3D object that contains the material properties of the object.</span>
		* 
		* @param	width	
		* <span lang="ja">横幅です。</span>
		* <span lang="en">Desired width or scaling factor if there's bitmap texture in material and no height is supplied.</span>
		* 
		* @param	height	
		* <span lang="ja">高さです。</span>
		* <span lang="en">Desired height.</span>
		* 
		* @param	segmentsW	
		* <span lang="ja">水平セグメントの数です。デフォルトは 1 です。</span>
		* <span lang="en"> Number of segments horizontally. Defaults to 1.</span>
		* 
		* @param	segmentsH	
		* <span lang="ja">垂直セグメントの数です。デフォルトは 1 です。</span>
		* <span lang="en">Number of segments vertically. Defaults to segmentsW.</span>
		* 
		* @example 次の例では平面を作成し、3Dシーンに平面を表示します。
		* <div class="listing"><pre>
		* import org.papervision3d.objects.primitives.Plane;
		* import org.papervision3d.materials.WireframeMaterial;
		* 
		* // マテリアルを作成
		* var material:WireframeMaterial = new WireframeMaterial(0x0000FF);
		* 
		* // プリミティブオブジェクトを作成
		* var obj:Plane = new Plane(material, 500, 500, 20, 20);
		* scene.addChild(obj);
		* </pre></div>
		* ※scene は BasicView クラスのプロパティー
		*/
		public function Plane( material:MaterialObject3D=null, width:Number=0, height:Number=0, segmentsW:Number=0, segmentsH:Number=0 )
		{
			super( material, new Array(), new Array(), null );
	
			this.segmentsW = segmentsW || DEFAULT_SEGMENTS; // Defaults to 1
			this.segmentsH = segmentsH || this.segmentsW;   // Defaults to segmentsW
	
			var scale :Number = DEFAULT_SCALE;
	
			if( ! height )
			{
				if( width )
					scale = width;
	
				if( material && material.bitmap )
				{
					width  = material.bitmap.width  * scale;
					height = material.bitmap.height * scale;
				}
				else
				{
					width  = DEFAULT_SIZE * scale;
					height = DEFAULT_SIZE * scale;
				}
			}
	
			buildPlane( width, height );
		}
	
		private function buildPlane( width:Number, height:Number ):void
		{
			var gridX    :Number = this.segmentsW;
			var gridY    :Number = this.segmentsH;
			var gridX1   :Number = gridX + 1;
			var gridY1   :Number = gridY + 1;
	
			var vertices :Array  = this.geometry.vertices;
			var faces    :Array  = this.geometry.faces;
	
			var textureX :Number = width /2;
			var textureY :Number = height /2;
	
			var iW       :Number = width / gridX;
			var iH       :Number = height / gridY;
	
			// Vertices
			for( var ix:int = 0; ix < gridX + 1; ix++ )
			{
				for( var iy:int = 0; iy < gridY1; iy++ )
				{
					var x :Number = ix * iW - textureX;
					var y :Number = iy * iH - textureY;
	
					vertices.push( new Vertex3D( x, y, 0 ) );
				}
			}
	
			// Faces
			var uvA :NumberUV;
			var uvC :NumberUV;
			var uvB :NumberUV;
	
			for(  ix = 0; ix < gridX; ix++ )
			{
				for(  iy= 0; iy < gridY; iy++ )
				{
					// Triangle A
					var a:Vertex3D = vertices[ ix     * gridY1 + iy     ];
					var c:Vertex3D = vertices[ ix     * gridY1 + (iy+1) ];
					var b:Vertex3D = vertices[ (ix+1) * gridY1 + iy     ];
	
					uvA =  new NumberUV( ix     / gridX, iy     / gridY );
					uvC =  new NumberUV( ix     / gridX, (iy+1) / gridY );
					uvB =  new NumberUV( (ix+1) / gridX, iy     / gridY );
	
					faces.push(new Triangle3D(this, [ a, b, c ], material, [ uvA, uvB, uvC ] ) );
	
					// Triangle B
					a = vertices[ (ix+1) * gridY1 + (iy+1) ];
					c = vertices[ (ix+1) * gridY1 + iy     ];
					b = vertices[ ix     * gridY1 + (iy+1) ];
	
					uvA =  new NumberUV( (ix+1) / gridX, (iy+1) / gridY );
					uvC =  new NumberUV( (ix+1) / gridX, iy      / gridY );
					uvB =  new NumberUV( ix      / gridX, (iy+1) / gridY );
					
					faces.push(new Triangle3D(this, [ a, b, c ], material, [ uvA, uvB, uvC ] ) );
				}
			}
	
			this.geometry.ready = true;
			
			if(Papervision3D.useRIGHTHANDED)
				this.geometry.flipFaces();
		}
	}
}
